#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
#include <thread>
#include <condition_variable>
#include <mutex>
#include "Log.hpp"
#include "Task.hpp"

#define NUM 4

class ThreadPool
{
private:
    std::queue<Task> task_queue;
    int num;
    bool stop;
    std::mutex _lock;                  // 锁
    std::condition_variable_any _cond; // 条件变量
    bool ready;

    ThreadPool(int _num = NUM)
        : stop(false), num(_num)
    {
    }

    ThreadPool(const ThreadPool &) = delete;
    static ThreadPool *single_instance;

public:
    static ThreadPool *GetInstance()
    {
        static std::mutex _mutex;
        if (single_instance == nullptr)
        {
            _mutex.lock();
            if (single_instance == nullptr)
            {
                single_instance = new ThreadPool();
                single_instance->InitThreadPool();
            }
            _mutex.unlock();
        }
        return single_instance;
    }

    void Lock()
    {
        _lock.lock();
    }

    void Unlock()
    {
        _lock.unlock();
    }

    bool TaskQueueIsEmpty()
    {
        return task_queue.empty();
    }

    static void ThreadRoutine(ThreadPool *args)
    {
        ThreadPool *tp = args;
        while (true)
        {
            Task task;
            // 加锁,取任务
            tp->Lock();
            while (tp->TaskQueueIsEmpty()) // 使用while循环防止伪唤醒，保证一定有任务才继续进行任务处理
            {
                // 队列为空
                tp->ThreadWait();
                // 醒来之后一定占有互斥锁
            }
            // 保证一定有任务
            tp->PopTask(task);
            tp->Unlock();
            // 解锁，处理任务
            task.ProcessOn();
        }
    }

    bool IsStop()
    {
        return stop;
    }

    void ThreadWait()
    {
        _cond.wait(_lock);
    }

    void ThreadWakeup()
    {
        _cond.notify_one();
    }

    bool InitThreadPool()
    {
        for (int i = 0; i < num; ++i)
        {
            try
            {
                std::thread td(ThreadRoutine, this);
                td.detach();
            }
            catch (const std::exception &e)
            {
                std::cerr << e.what() << '\n';
                LOG(FATAL, "create thread pool error!");
                return false;
            }
        }
        LOG(INFO, "create thread pool success!");
        return true;
    }

    // 放入任务
    void PushTask(const Task &task)
    {
        {
            std::unique_lock<std::mutex> lck(_lock);
            task_queue.push(task);
        }
        ThreadWakeup();
    }

    // 拿出任务
    void PopTask(Task &task)
    {
        task = task_queue.front();
        task_queue.pop();
    }

    ~ThreadPool()
    {
    }
};

ThreadPool *ThreadPool::single_instance = nullptr;

void test()
{
    
}
